// 《围棋》作者版权所有。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

// 包modget实现了模块感知的“go get”命令。
package modget

// goget的参数是带有可选版本查询的模式，而
// 版本查询默认为“升级”。
// 
// 这些模式通常被解释为包模式。但是，如果
// 模式与包不匹配，它将被解释为*module*
// 模式。对于依赖于
// 模块（或包含包的模块）的选定版本的版本查询，如“升级”和“补丁”，
// 模式是否表示在应用更新时包或模块可能会发生更改
// 参见mod_get_patchmod.txt中的示例。
// 
// 还有其他一些模棱两可的案件需要解决。一个包可以存在于
// 同一版本的两个不同模块中：例如，包
// 例如。com/foo可以在模块示例中找到。com和模块
// 示例。com/foo，这些模块可能有独立的v0。1.0标签——因此
// input示例。com/foo@v0.1.0'可以在语法上指
// 从任一模块加载的包的变体！（请参阅mod_get_buzzalize_pkg.txt。）
// 如果参数不明确，用户通常可以通过指定
// 为所涉及的*所有*潜在模块路径指定显式版本来消除歧义。

import (
	"context"
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"sort"
	"strings"
	"sync"

	"cmd/go/internal/base"
	"cmd/go/internal/imports"
	"cmd/go/internal/modfetch"
	"cmd/go/internal/modload"
	"cmd/go/internal/par"
	"cmd/go/internal/search"
	"cmd/go/internal/work"

	"golang.org/x/mod/modfile"
	"golang.org/x/mod/module"
	"golang.org/x/mod/semver"
)

var CmdGet = &base.Command{
	// 注意：下面的标志是明确列出的，因为它们是最常见的。
	// 不要发送CLs删除它们，因为它们被[get flags]覆盖。
	UsageLine: "go get [-t] [-u] [-v] [build flags] [packages]",
	Short:     "add dependencies to current module and install them",
	Long: `
Get resolves its command-line arguments to packages at specific module versions,
updates go.mod to require those versions, and downloads source code into the
module cache.

To add a dependency for a package or upgrade it to its latest version:

	go get example.com/pkg

To upgrade or downgrade a package to a specific version:

	go get example.com/pkg@v1.2.3

To remove a dependency on a module and downgrade modules that require it:

	go get example.com/mod@none

See https:// golang。org/ref/mod#获取详细信息。郭朗。org/ref/mod#有关详细信息，请转至安装。

In earlier versions of Go, 'go get' was used to build and install packages.
Now, 'go get' is dedicated to adjusting dependencies in go.mod. 'go install'
may be used to build and install commands instead. When a version is specified,
'go install' runs in module-aware mode and ignores the go.mod file in the
current directory. For example:

	go install example.com/pkg@v1.2.3
	go install example.com/pkg@latest


'go get' accepts the following flags.

The -t flag instructs get to consider modules needed to build tests of
packages specified on the command line.

The -u flag instructs get to update modules providing dependencies
of packages named on the command line to use newer minor or patch
releases when available.

The -u=patch flag (not -u patch) also instructs get to update dependencies,
but changes the default to select patch releases.

When the -t and -u flags are used together, get will update
test dependencies as well.

The -x flag prints commands as they are executed. This is useful for
debugging version control commands when a module is downloaded directly
from a repository.

For more about modules, see https:// golang。org/ref/mod。

For more about specifying packages, see 'go help packages'.

This text describes the behavior of get using modules to manage source
code and dependencies. If instead the go command is running in GOPATH
mode, the details of get's flags and effects change, as does 'go help get'.
See 'go help gopath-get'.

See also: go build, go install, go clean, go mod.
	`,
}

// 请注意，此帮助文本是一个权宜之计，可使模块识别获取帮助文本
// 即使在非模块设置中也可用。当删除旧的get 
// 时，应该将其删除。这不应被视为开创了一个使用带破折号的分层
// 帮助名称的先例。
var HelpModuleGet = &base.Command{
	UsageLine: "module-get",
	Short:     "module-aware go get",
	Long: `
The 'go get' command changes behavior depending on whether the
go command is running in module-aware mode or legacy GOPATH mode.
This help text, accessible as 'go help module-get' even in legacy GOPATH mode,
describes 'go get' as it operates in module-aware mode.

Usage: ` + CmdGet.UsageLine + `
` + CmdGet.Long,
}

var HelpVCS = &base.Command{
	UsageLine: "vcs",
	Short:     "controlling version control with GOVCS",
	Long: `
The 'go get' command can run version control commands like git
to download imported code. This functionality is critical to the decentralized
Go package ecosystem, in which code can be imported from any server,
but it is also a potential security problem, if a malicious server finds a
way to cause the invoked version control command to run unintended code.

To balance the functionality and security concerns, the 'go get' command
by default will only use git and hg to download code from public servers.
But it will use any known version control system (bzr, fossil, git, hg, svn)
to download code from private servers, defined as those hosting packages
matching the GOPRIVATE variable (see 'go help private'). The rationale behind
allowing only Git and Mercurial is that these two systems have had the most
attention to issues of being run as clients of untrusted servers. In contrast,
Bazaar, Fossil, and Subversion have primarily been used in trusted,
authenticated environments and are not as well scrutinized as attack surfaces.

The version control command restrictions only apply when using direct version
control access to download code. When downloading modules from a proxy,
'go get' uses the proxy protocol instead, which is always permitted.
By default, the 'go get' command uses the Go module mirror (proxy.golang.org)
for public packages and only falls back to version control for private
packages or when the mirror refuses to serve a public package (typically for
legal reasons). Therefore, clients can still access public code served from
Bazaar, Fossil, or Subversion repositories by default, because those downloads
use the Go module mirror, which takes on the security risk of running the
version control commands using a custom sandbox.

The GOVCS variable can be used to change the allowed version control systems
for specific packages (identified by a module or import path).
The GOVCS variable applies when building package in both module-aware mode
and GOPATH mode. When using modules, the patterns match against the module path.
When using GOPATH, the patterns match against the import path corresponding to
the root of the version control repository.

The general form of the GOVCS setting is a comma-separated list of
pattern:vcslist rules. The pattern is a glob pattern that must match
one or more leading elements of the module or import path. The vcslist
is a pipe-separated list of allowed version control commands, or "all"
to allow use of any known command, or "off" to disallow all commands.
Note that if a module matches a pattern with vcslist "off", it may still be
downloaded if the origin server uses the "mod" scheme, which instructs the
go command to download the module using the GOPROXY protocol.
The earliest matching pattern in the list applies, even if later patterns
might also match.

For example, consider:

	GOVCS=github.com:git,evil.com:off,*:git|hg

With this setting, code with a module or import path beginning with
github.com/ can only use git; paths on evil.com cannot use any version
control command, and all other paths (* matches everything) can use
only git or hg.

The special patterns "public" and "private" match public and private
module or import paths. A path is private if it matches the GOPRIVATE
variable; otherwise it is public.

If no rules in the GOVCS variable match a particular module or import path,
the 'go get' command applies its default rule, which can now be summarized
in GOVCS notation as 'public:git|hg,private:all'.

To allow unfettered use of any version control system for any package, use:

	GOVCS=*:all

To disable all use of version control, use:

	GOVCS=*:off

The 'go env -w' command (see 'go help env') can be used to set the GOVCS
variable for future go command invocations.
`,
}

var (
	getD        = CmdGet.Flag.Bool("d", true, "")
	getF        = CmdGet.Flag.Bool("f", false, "")
	getFix      = CmdGet.Flag.Bool("fix", false, "")
	getM        = CmdGet.Flag.Bool("m", false, "")
	getT        = CmdGet.Flag.Bool("t", false, "")
	getU        upgradeFlag
	getInsecure = CmdGet.Flag.Bool("insecure", false, "")
	// /-v是cfg。BuildV 
)

// upgradeFlag是一个自定义标志。值为-u.
type upgradeFlag struct {
	rawVersion string
	version    string
}

func (*upgradeFlag) IsBoolFlag() bool { return true } // allow-u 

func (v *upgradeFlag) Set(s string) error {
	if s == "false" {
		v.version = ""
		v.rawVersion = ""
	} else if s == "true" {
		v.version = "upgrade"
		v.rawVersion = ""
	} else {
		v.version = s
		v.rawVersion = s
	}
	return nil
}

func (v *upgradeFlag) String() string { return "" }

func init() {
	work.AddBuildFlags(CmdGet, work.OmitModFlag)
	CmdGet.Run = runGet // break init loop 
	CmdGet.Flag.Var(&getU, "u", "")
}

func runGet(ctx context.Context, cmd *base.Command, args []string) {
	switch getU.version {
	case "", "upgrade", "patch":
		// ok 
	default:
		base.Fatalf("go: unknown upgrade flag -u=%s", getU.rawVersion)
	}
	// TODO（#43684）：在未来（Go 1.20），警告-d是禁止的。
	if !*getD {
		base.Fatalf("go: -d flag may not be disabled")
	}
	if *getF {
		fmt.Fprintf(os.Stderr, "go: -f flag is a no-op when using modules\n")
	}
	if *getFix {
		fmt.Fprintf(os.Stderr, "go: -fix flag is a no-op when using modules\n")
	}
	if *getM {
		base.Fatalf("go: -m flag is no longer supported")
	}
	if *getInsecure {
		base.Fatalf("go: -insecure flag is no longer supported; use GOINSECURE instead")
	}

	modload.ForceUseModules = true

	// 不允许对Go进行任何更新。mod，直到我们应用了
	// 所有请求的更改，并检查结果是否与
	// 请求的内容匹配。
	modload.ExplicitWriteGoMod = true

	// 允许在模块外部查找模块的导入路径。与其他命令不同，
	// /'go get'应该可以执行此操作。
	modload.AllowMissingModuleImports()

	// “go get”不再构建或安装软件包，因此如果没有go，就没有什么可做的了。mod文件。
	// TODO（#40775）：生成modload。Init返回ErrNoModRoot而不是退出。
	// 我们可以通过打印不同的消息来处理这个问题。
	modload.Init()
	if !modload.HasModRoot() {
		base.Fatalf("go: go.mod file not found in current directory or any parent directory.\n" +
			"\t'go get' is no longer supported outside a module.\n" +
			"\tTo build and install a command, use 'go install' with a version,\n" +
			"\tlike 'go install example.com/cmd@latest'\n" +
			"\tFor more information, see https:// golang。org/doc/go-get-install-deprecation\n“+
			"\tor run 'go help get' or 'go help install'.")
	}

	queries := parseArgs(ctx, args)

	r := newResolver(ctx, queries)
	r.performLocalQueries(ctx)
	r.performPathQueries(ctx)

	for {
		r.performWildcardQueries(ctx)
		r.performPatternAllQueries(ctx)

		if changed := r.resolveQueries(ctx, queries); changed {
			// /“go-get”参数可以是（通常是）包模式，而不是
			// /（仅此而已）模块。任何模块都可以提供其导入路径前缀为
			// 的包，通配符甚至可以匹配模块
			// 中具有完全不同路径的包。由于这些影响，并且由于对模块的选定版本的任何更改都可能带来全新的模块路径作为依赖项，因此每当更改构建列表时，我们都需要重新发出查询。
			// 
			// 给定模块的任何版本查询的结果——即使是“升级”或
			// “补丁”——总是相对于
			// 开始时的构建列表，而不是中间状态，因此
			// 是可终止的，因此是可计算的，而对
			// 每个模块的选定版本的限制只能随着我们的迭代而缩小。
			// 
			// “all”在功能上与通配符模式非常相似。主模块导入的
			// 包集不变，包含每个此类包的模块的查询
			// 结果也不变
			// （在应用
			// 查询之前，它始终相对于初始构建列表）。所以“all”查询结果改变
			// 是指一些匹配的包从构建列表
			// 中的一个模块移动到另一个模块，这种情况不应该经常发生。
			continue
		}

		// 加载导入时，我们检测到以下情况：
		// 
		// -缺少需要从
		// 当前构建列表外部解决的传递依赖项（请注意，这些可能会为现有
		// 模式查询添加新匹配项！）
		// 
		// -与任何其他查询不匹配的可传递依赖项，
		// 但由于-u标志
		// 
		// -不明确的导入错误，需要升级。
		// TODO（#27899）：尝试自动解决不明确的导入错误。一切都成功了。更新开始。摩登派青年
		upgrades := r.findAndUpgradeImports(ctx, queries)
		if changed := r.applyUpgrades(ctx, upgrades); changed {
			continue
		}

		r.findMissingWildcards(ctx)
		if changed := r.resolveQueries(ctx, r.wildcardQueries); changed {
			continue
		}

		break
	}

	r.checkWildcardVersions(ctx)

	var pkgPatterns []string
	for _, q := range queries {
		if q.matchesPackages {
			pkgPatterns = append(pkgPatterns, q.pattern)
		}
	}
	r.checkPackageProblems(ctx, pkgPatterns)

	oldReqs := reqsFromGoMod(modload.ModFile())

	if err := modload.WriteGoMod(ctx); err != nil {
		base.Fatalf("go: %v", err)
	}

	newReqs := reqsFromGoMod(modload.ModFile())
	r.reportChanges(oldReqs, newReqs)
}

// parseArgs解析命令行参数并报告错误。
// 
// 命令行参数的形式如下path@version或者简单地用
// implicit@upgrade。path@none就是“降级”。
func parseArgs(ctx context.Context, rawArgs []string) []*query {
	defer base.ExitIfErrors()

	var queries []*query
	for _, arg := range search.CleanPatterns(rawArgs) {
		q, err := newQuery(arg)
		if err != nil {
			base.Errorf("go: %v", err)
			continue
		}

		// 如果没有参数，CleanPatterns返回“”。将原始
		// 字符串设置回“”以获得更好的错误。
		if len(rawArgs) == 0 {
			q.raw = ""
		}

		// 防止“go get x.go”这一常见错误。
		// 请注意，包和模块路径可能以“.”结尾。go'，因此，如果参数没有版本，或者没有斜杠，或者引用了现有文件，则只打印一个错误
		// 。
		if strings.HasSuffix(q.raw, ".go") && q.rawVersion == "" {
			if !strings.Contains(q.raw, "/") {
				base.Errorf("go: %s: arguments must be package or module paths", q.raw)
				continue
			}
			if fi, err := os.Stat(q.raw); err == nil && !fi.IsDir() {
				base.Errorf("go: %s exists as a file, but 'go get' requires package arguments", q.raw)
				continue
			}
		}

		queries = append(queries, q)
	}

	return queries
}

type resolver struct {
	localQueries      []*query // 查询绝对或相对路径
	pathQueries       []*query // 按原始顺序打包路径文字查询
	wildcardQueries   []*query // 按原始顺序打包路径通配符查询
	patternAllQueries []*query // 带模式“all”的查询

	// 索引的“none”查询。这些也包括在上面的切片中；
	// 它们在这里被编入索引，以加速noneForPath。
	nonesByPath   map[string]*query // 路径文字“@none”查询由路径
	wildcardNones []*query          // 通配符“@none”查询

	// resolvedVersion将每个模块路径映射到最终生成列表中必须选择的模块版本，以及将模块解析到该版本的第一个查询
	// 的“原因”）。
	resolvedVersion map[string]versionReason

	buildList        []module.Version
	buildListVersion map[string]string // 构建列表索引（模块路径）→ 版本）

	initialVersion map[string]string // 初始构建列表在“go get”开始处的索引

	missing []pathSet // 缺少传递依赖项的候选

	work *par.Queue

	matchInModuleCache par.Cache
}

type versionReason struct {
	version string
	reason  *query
}

func newResolver(ctx context.Context, queries []*query) *resolver {
	// LoadModGraph也设置modload。各种解析器
	// 方法所需的目标。
	const defaultGoVersion = ""
	mg := modload.LoadModGraph(ctx, defaultGoVersion)

	buildList := mg.BuildList()
	initialVersion := make(map[string]string, len(buildList))
	for _, m := range buildList {
		initialVersion[m.Path] = m.Version
	}

	r := &resolver{
		work:             par.NewQueue(runtime.GOMAXPROCS(0)),
		resolvedVersion:  map[string]versionReason{},
		buildList:        buildList,
		buildListVersion: initialVersion,
		initialVersion:   initialVersion,
		nonesByPath:      map[string]*query{},
	}

	for _, q := range queries {
		if q.pattern == "all" {
			r.patternAllQueries = append(r.patternAllQueries, q)
		} else if q.patternIsLocal {
			r.localQueries = append(r.localQueries, q)
		} else if q.isWildcard() {
			r.wildcardQueries = append(r.wildcardQueries, q)
		} else {
			r.pathQueries = append(r.pathQueries, q)
		}

		if q.version == "none" {
			// 索引“none”查询以提高noneForPath的效率。
			if q.isWildcard() {
				r.wildcardNones = append(r.wildcardNones, q)
			} else {
				// 对于同一路径的所有“<path>@none”查询都是相同的；我们只需要索引一份。
				r.nonesByPath[q.pattern] = q
			}
		}
	}

	return r
}

// initialSelected返回模块的版本，该模块具有在该'go get'调用开始时选择的给定路径。
func (r *resolver) initialSelected(mPath string) (version string) {
	v, ok := r.initialVersion[mPath]
	if !ok {
		return "none"
	}
	return v
}

// selected返回模块的版本，该模块具有给定路径，即在冲突解决程序的当前生成列表中选择的
// 路径。
func (r *resolver) selected(mPath string) (version string) {
	v, ok := r.buildListVersion[mPath]
	if !ok {
		return "none"
	}
	return v
}

// noneForPath返回与给定模块路径匹配的“none”查询，如果不存在这样的查询，则返回“none”查询，或返回find==false。
func (r *resolver) noneForPath(mPath string) (nq *query, found bool) {
	if nq = r.nonesByPath[mPath]; nq != nil {
		return nq, true
	}
	for _, nq := range r.wildcardNones {
		if nq.matchesPath(mPath) {
			return nq, true
		}
	}
	return nil, false
}

// queryModule包装modload。查询，替换r.checkAllowedOr来决定
// 允许的版本。
func (r *resolver) queryModule(ctx context.Context, mPath, query string, selected func(string) string) (module.Version, error) {
	current := r.initialSelected(mPath)
	rev, err := modload.Query(ctx, mPath, query, current, r.checkAllowedOr(query, selected))
	if err != nil {
		return module.Version{}, err
	}
	return module.Version{Path: mPath, Version: rev.Version}, nil
}

// queryPackage包装modload。QueryPackage，用r.checkAllowedOr代替
// 决定允许的版本。
func (r *resolver) queryPackages(ctx context.Context, pattern, query string, selected func(string) string) (pkgMods []module.Version, err error) {
	results, err := modload.QueryPackages(ctx, pattern, query, selected, r.checkAllowedOr(query, selected))
	if len(results) > 0 {
		pkgMods = make([]module.Version, 0, len(results))
		for _, qr := range results {
			pkgMods = append(pkgMods, qr.Mod)
		}
	}
	return pkgMods, err
}

// queryPattern包装modload。QueryPattern，替换r.checkAllowedOr以决定允许的版本。
func (r *resolver) queryPattern(ctx context.Context, pattern, query string, selected func(string) string) (pkgMods []module.Version, mod module.Version, err error) {
	results, modOnly, err := modload.QueryPattern(ctx, pattern, query, selected, r.checkAllowedOr(query, selected))
	if len(results) > 0 {
		pkgMods = make([]module.Version, 0, len(results))
		for _, qr := range results {
			pkgMods = append(pkgMods, qr.Mod)
		}
	}
	if modOnly != nil {
		mod = modOnly.Mod
	}
	return pkgMods, mod, err
}

// checkAllowedOr类似于modload。选中Allowed，但它始终允许请求的
// 和当前版本（即使它们被撤回或以其他方式排除）。
func (r *resolver) checkAllowedOr(requested string, selected func(string) string) modload.AllowedFunc {
	return func(ctx context.Context, m module.Version) error {
		if m.Version == requested {
			return modload.CheckExclusions(ctx, m)
		}
		if (requested == "upgrade" || requested == "patch") && m.Version == selected(m.Path) {
			return nil
		}
		return modload.CheckAllowed(ctx, m)
	}
}

// matchInModule是围绕modload的缓存包装器。匹配模块。
func (r *resolver) matchInModule(ctx context.Context, pattern string, m module.Version) (packages []string, err error) {
	type key struct {
		pattern string
		m       module.Version
	}
	type entry struct {
		packages []string
		err      error
	}

	e := r.matchInModuleCache.Do(key{pattern, m}, func() any {
		match := modload.MatchInModule(ctx, pattern, m, imports.AnyTags())
		if len(match.Errs) > 0 {
			return entry{match.Pkgs, match.Errs[0]}
		}
		return entry{match.Pkgs, nil}
	}).(entry)

	return e.packages, e.err
}

// QueryOne为每个与q模式匹配的模块向q添加一个候选集。
// 每个候选集只有一个可能的模块版本：匹配的
// 版本为“无”的模块。
// 
// 我们首先将“go get”的参数解释为包，然后返回到
// 模块。但是，版本“none”中不存在模块，因此该版本中也不存在
// 包：我们知道参数不能匹配
// 任何包，因此它必须匹配模块。
func (r *resolver) queryNone(ctx context.Context, q *query) {
	if search.IsMetaPackage(q.pattern) {
		panic(fmt.Sprintf("internal error: queryNone called with pattern %q", q.pattern))
	}

	if !q.isWildcard() {
		q.pathOnce(q.pattern, func() pathSet {
			hasModRoot := modload.HasModRoot()
			if hasModRoot && modload.MainModules.Contains(q.pattern) {
				v := module.Version{Path: q.pattern}
				// 用户明确要求将自己的模块降级为
				// 版本“无”。这并不是一个完全不合理的请求：它可能意味着“降级掉所有依赖于主模块的任何
				// 显式版本的内容”，或者“降级掉
				// 与主模块路径相同的包，在模块
				// 中找到，前缀为主模块的路径”。
				// 
				// 然而，这两种行为都不符合查询的简单含义。为了减少混淆，请明确拒绝
				// 查询。
				return errSet(&modload.QueryMatchesMainModulesError{MainModules: []module.Version{v}, Pattern: q.pattern, Query: q.version})
			}

			return pathSet{mod: module.Version{Path: q.pattern, Version: "none"}}
		})
	}

	for _, curM := range r.buildList {
		if !q.matchesPath(curM.Path) {
			continue
		}
		q.pathOnce(curM.Path, func() pathSet {
			if modload.HasModRoot() && curM.Version == "" && modload.MainModules.Contains(curM.Path) {
				return errSet(&modload.QueryMatchesMainModulesError{MainModules: []module.Version{curM}, Pattern: q.pattern, Query: q.version})
			}
			return pathSet{mod: module.Version{Path: curM.Path, Version: "none"}}
		})
	}
}

func (r *resolver) performLocalQueries(ctx context.Context) {
	for _, q := range r.localQueries {
		q.pathOnce(q.pattern, func() pathSet {
			absDetail := ""
			if !filepath.IsAbs(q.pattern) {
				if absPath, err := filepath.Abs(q.pattern); err == nil {
					absDetail = fmt.Sprintf(" (%s)", absPath)
				}
			}

			// 像C:\foo这样的绝对路径和像..这样的相对路径/福。。。
			// 仅限于主模块中的匹配包。
			pkgPattern, mainModule := modload.MainModules.DirImportPath(ctx, q.pattern)
			if pkgPattern == "." {
				modload.MustHaveModRoot()
				var modRoots []string
				for _, m := range modload.MainModules.Versions() {
					modRoots = append(modRoots, modload.MainModules.ModRoot(m))
				}
				var plural string
				if len(modRoots) != 1 {
					plural = "s"
				}
				return errSet(fmt.Errorf("%s%s is not within module%s rooted at %s", q.pattern, absDetail, plural, strings.Join(modRoots, ", ")))
			}

			match := modload.MatchInModule(ctx, pkgPattern, mainModule, imports.AnyTags())
			if len(match.Errs) > 0 {
				return pathSet{err: match.Errs[0]}
			}

			if len(match.Pkgs) == 0 {
				if q.raw == "" || q.raw == "." {
					return errSet(fmt.Errorf("no package to get in current directory"))
				}
				if !q.isWildcard() {
					modload.MustHaveModRoot()
					return errSet(fmt.Errorf("%s%s is not a package in module rooted at %s", q.pattern, absDetail, modload.MainModules.ModRoot(mainModule)))
				}
				search.WarnUnmatched([]*search.Match{match})
				return pathSet{}
			}

			return pathSet{pkgMods: []module.Version{mainModule}}
		})
	}
}

// performWildcardQueries为每个模式
// 为通配符的查询填充候选项。
// 
// 给定模块路径匹配（或包含包
// 匹配）的候选通配符查询仅依赖于初始构建列表，但模块集
// 可能会被其他查询扩展，因此，每当一个可能匹配的模块路径被添加到
// 构建列表时，通配符查询都需要重新计算。
func (r *resolver) performWildcardQueries(ctx context.Context) {
	for _, q := range r.wildcardQueries {
		q := q
		r.work.Add(func() {
			if q.version == "none" {
				r.queryNone(ctx, q)
			} else {
				r.queryWildcard(ctx, q)
			}
		})
	}
	<-r.work.Idle()
}

// queryWildcard为每个模块的q添加一个候选集：
// /-模块的某些版本已经在构建列表中，并且
// /-该模块存在于与q.version匹配的某个版本中，并且
// /-模块路径本身与q.pattern匹配，或者
// q.version的模块与q.pattern匹配。
func (r *resolver) queryWildcard(ctx context.Context, q *query) {
	// 对于通配符模式，modload。QueryPattern仅标识模块
	// 匹配通配符之前的路径前缀。但是，构建ABCFDG 
	// 我们想匹配现有依赖项中的任何包，但我们只想在没有其他发现的情况下解决新的依赖项。
	for _, curM := range r.buildList {
		if !q.canMatchInModule(curM.Path) {
			continue
		}
		q.pathOnce(curM.Path, func() pathSet {
			if _, hit := r.noneForPath(curM.Path); hit {
				// 此模块正在被删除，因此它将不再位于生成列表
				// （因此将不再匹配该模式）。
				return pathSet{}
			}

			if modload.MainModules.Contains(curM.Path) && !versionOkForMainModule(q.version) {
				if q.matchesPath(curM.Path) {
					return errSet(&modload.QueryMatchesMainModulesError{
						MainModules: []module.Version{curM},
						Pattern:     q.pattern,
						Query:       q.version,
					})
				}

				packages, err := r.matchInModule(ctx, q.pattern, curM)
				if err != nil {
					return errSet(err)
				}
				if len(packages) > 0 {
					return errSet(&modload.QueryMatchesPackagesInMainModuleError{
						Pattern:  q.pattern,
						Query:    q.version,
						Packages: packages,
					})
				}

				return r.tryWildcard(ctx, q, curM)
			}

			m, err := r.queryModule(ctx, curM.Path, q.version, r.initialSelected)
			if err != nil {
				if !isNoSuchModuleVersion(err) {
					// 我们无法判断是否存在匹配的版本。
					return errSet(err)
				}
				// 没有curM的版本。与查询匹配的路径。

				// 我们还没有检查curM在其当前选择的版本中是否包含任何匹配的包，或者curM是否。路径本身与q匹配。如果
				// 其中一个条件成立，*并且*没有其他查询更改
				// curM的选定版本，那么我们将无法检查通配符版本。
				// （这可能是个错误，但现在说还为时过早。）
				// 
				// 然而，即使是这样，其他一些查询的传递性要求
				// 也可能会将该模块从构建列表中完全降级，在这种情况下，
				// 模式将不再包含它，并且不会出错。
				// 
				// 无论哪种方式，都要在查询上下赌注，而不是马上出错。
				return pathSet{}
			}

			return r.tryWildcard(ctx, q, m)
		})
	}

	// 即使没有匹配的模块，我们也不应该查询一个新模块来提供
	// 模式：其他一些查询可能会导致新的要求，即
	// 将匹配通配符。相反，我们将签入FindAdminsingWildcards。
}

// tryWildcard返回模块m匹配查询q的路径集。
// 如果m实际上与q不匹配，tryWildcard返回一个空路径集。
func (r *resolver) tryWildcard(ctx context.Context, q *query, m module.Version) pathSet {
	mMatches := q.matchesPath(m.Path)
	packages, err := r.matchInModule(ctx, q.pattern, m)
	if err != nil {
		return errSet(err)
	}
	if len(packages) > 0 {
		return pathSet{pkgMods: []module.Version{m}}
	}
	if mMatches {
		return pathSet{mod: m}
	}
	return pathSet{}
}

// FindAdminsingWildcards为r.wildcardQueries中尚未解析为包含包的任何版本的每个查询添加候选集。
func (r *resolver) findMissingWildcards(ctx context.Context) {
	for _, q := range r.wildcardQueries {
		if q.version == "none" || q.matchesPackages {
			continue // q未“丢失”
		}
		r.work.Add(func() {
			q.pathOnce(q.pattern, func() pathSet {
				pkgMods, mod, err := r.queryPattern(ctx, q.pattern, q.version, r.initialSelected)
				if err != nil {
					if isNoSuchPackageVersion(err) && len(q.resolved) > 0 {
						// q已解析一个或多个模块，但不匹配任何包。没关系：这个模式只是一个模块模式，我们不需要添加更多的模块来满足它。
						return pathSet{}
					}
					return errSet(err)
				}

				return pathSet{pkgMods: pkgMods, mod: mod}
			})
		})
	}
	<-r.work.Idle()
}

// 如果生成列表中的任何模块具有与通配符模式匹配的查询的
// 路径（或包含包），但
// 具有与查询不匹配的所选版本，则checkWildcardVersions会报告错误。
func (r *resolver) checkWildcardVersions(ctx context.Context) {
	defer base.ExitIfErrors()

	for _, q := range r.wildcardQueries {
		for _, curM := range r.buildList {
			if !q.canMatchInModule(curM.Path) {
				continue
			}
			if !q.matchesPath(curM.Path) {
				packages, err := r.matchInModule(ctx, q.pattern, curM)
				if len(packages) == 0 {
					if err != nil {
						reportError(q, err)
					}
					continue // curM与q无关。
				}
			}

			rev, err := r.queryModule(ctx, curM.Path, q.version, r.initialSelected)
			if err != nil {
				reportError(q, err)
				continue
			}
			if rev.Version == curM.Version {
				continue // curM已与q匹配。
			}

			if !q.matchesPath(curM.Path) {
				m := module.Version{Path: curM.Path, Version: rev.Version}
				packages, err := r.matchInModule(ctx, q.pattern, m)
				if err != nil {
					reportError(q, err)
					continue
				}
				if len(packages) == 0 {
					// curM在其原始版本中包含与q匹配的路径。模式
					// 。版本没有，所以（有些矛盾）如果
					// 我们更改了curM的版本，它将不再匹配查询。
					var version any = m
					if rev.Version != q.version {
						version = fmt.Sprintf("%s@%s (%s)", m.Path, q.version, m.Version)
					}
					reportError(q, fmt.Errorf("%v matches packages in %v but not %v: specify a different version for module %s", q, curM, version, m.Path))
					continue
				}
			}

			// 由于queryModule成功，并且curM或其中一个包
			// 包含匹配的q.pattern，我们应该选择curM匹配q的版本
			// 或报告冲突错误（并退出）。
			// 如果我们还在这里，但版本不匹配，
			// 出现了严重问题。
			reportError(q, fmt.Errorf("internal error: selected %v instead of %v", curM, rev.Version))
		}
	}
}

// performPathQueries为模式为
// 路径文字的每个查询填充候选项。
// 
// 路径文本的候选包和模块只依赖于
// 初始构建列表，而不是当前构建列表，因此我们只需要查询一次路径
// 文本。
func (r *resolver) performPathQueries(ctx context.Context) {
	for _, q := range r.pathQueries {
		q := q
		r.work.Add(func() {
			if q.version == "none" {
				r.queryNone(ctx, q)
			} else {
				r.queryPath(ctx, q)
			}
		})
	}
	<-r.work.Idle()
}

// queryPath为路径为q.pattern的包将候选集添加到q。
// 候选集由所有可以提供q.pattern的模块组成，并且具有与q匹配的版本，加上（如果存在）路径
// 本身就是q.pattern的模块（在匹配的版本）。
func (r *resolver) queryPath(ctx context.Context, q *query) {
	q.pathOnce(q.pattern, func() pathSet {
		if search.IsMetaPackage(q.pattern) || q.isWildcard() {
			panic(fmt.Sprintf("internal error: queryPath called with pattern %q", q.pattern))
		}
		if q.version == "none" {
			panic(`internal error: queryPath called with version "none"`)
		}

		if search.IsStandardImportPath(q.pattern) {
			stdOnly := module.Version{}
			packages, _ := r.matchInModule(ctx, q.pattern, stdOnly)
			if len(packages) > 0 {
				if q.rawVersion != "" {
					return errSet(fmt.Errorf("can't request explicit version %q of standard library package %s", q.version, q.pattern))
				}

				q.matchesPackages = true
				return pathSet{} // 标准库不需要模块。
			}
		}

		pkgMods, mod, err := r.queryPattern(ctx, q.pattern, q.version, r.initialSelected)
		if err != nil {
			return errSet(err)
		}
		return pathSet{pkgMods: pkgMods, mod: mod}
	})
}

// performPatternAllQueries为
// 模式为“all”的每个查询填充候选项。
// 
// 在“all”中，给定包的候选模块仅依赖于初始
// 构建列表，但我们无法跟踪给定包的依赖关系，直到我们知道选择了哪个候选模块，并且该选择可能取决于其他查询的
// 结果。每当
// 解析“all”中一个或多个包的模块时，我们需要重新评估“all”查询。
func (r *resolver) performPatternAllQueries(ctx context.Context) {
	if len(r.patternAllQueries) == 0 {
		return
	}

	findPackage := func(ctx context.Context, path string, m module.Version) (versionOk bool) {
		versionOk = true
		for _, q := range r.patternAllQueries {
			q.pathOnce(path, func() pathSet {
				pkgMods, err := r.queryPackages(ctx, path, q.version, r.initialSelected)
				if len(pkgMods) != 1 || pkgMods[0] != m {
					// 对于给定的路径，除了m之外还有其他候选路径，所以我们不能确定m实际上是被选择来提供包的模块。暂时不要加载它的依赖项，因为在我们解析正确的
					// 版本后，它们可能不再是依赖项。
					versionOk = false
				}
				return pathSet{pkgMods: pkgMods, err: err}
			})
		}
		return versionOk
	}

	r.loadPackages(ctx, []string{"all"}, findPackage)

	// 由于我们同时建立了候选人名单，他们可能处于不确定的顺序。我们希望“go get”是完全确定的，
	// 包括它选择报告的错误，所以将候选
	// 排序为确定但任意的顺序。
	for _, q := range r.patternAllQueries {
		sort.Slice(q.candidates, func(i, j int) bool {
			return q.candidates[i].path < q.candidates[j].path
		})
	}
}

// FindUpgradeImports为每个包返回一个路径集，该路径集在生成列表中尚未包含
// 但由与
// 给定查询匹配的包传递导入（必须已解决）。
// 
// 如果设置了getU标志（“-u”），FindUpgradeImports还会为每个模块返回一个
// 路径集，该路径集不受任何其他
// 命令行参数的约束，并且具有可用的匹配升级。
func (r *resolver) findAndUpgradeImports(ctx context.Context, queries []*query) (upgrades []pathSet) {
	patterns := make([]string, 0, len(queries))
	for _, q := range queries {
		if q.matchesPackages {
			patterns = append(patterns, q.pattern)
		}
	}
	if len(patterns) == 0 {
		return nil
	}

	// mu保护对升级的并发写入，加载后将对其进行排序
	// （以恢复确定性）。
	var mu sync.Mutex

	findPackage := func(ctx context.Context, path string, m module.Version) (versionOk bool) {
		version := "latest"
		if m.Path != "" {
			if getU.version == "" {
				// 用户没有要求我们升级可传递依赖项。
				return true
			}
			if _, ok := r.resolvedVersion[m.Path]; ok {
				// 我们无法隐式升级m，因为它的版本由
				// 一个显式模式参数决定。
				return true
			}
			version = getU.version
		}

		// 与其他查询不同，“-u”标志在应用到目前为止的更改后相对于生成列表而不是初始生成列表进行升级。
		// 这有两个原因：
		// 
		// /-“-u”标志有意应用于可传递依赖项，
		// 在应用
		// 其他版本更改之前，可能不知道或甚至无法解决。
		// 
		// -与其他参数不同，“-u”标志不会导致版本
		// 与其他查询冲突。（另一个查询总是赢。）

		pkgMods, err := r.queryPackages(ctx, path, version, r.selected)
		for _, u := range pkgMods {
			if u == m {
				// 所选软件包版本已适当升级；没有必要改变它。
				return true
			}
		}

		if err != nil {
			if isNoSuchPackageVersion(err) || (m.Path == "" && module.CheckPath(path) != nil) {
				// 我们找不到该软件包，因为它在最新版本的任何模块中都不存在。（请注意，由于替换，通常可能存在无效的模块路径
				// 因此我们至少需要
				// 运行查询来检查这些路径。）
				// 
				// 我们无法更改版本来修复该软件包，因此请保留
				// 它未解决。或者其他一些查询（可能是一个通配符匹配一个
				// 新添加的对其他丢失包的依赖项）将填补
				// 空白，或者我们将在
				// 最后的LoadPackages调用中报告一个错误（具有更好的导入堆栈）。
				return true
			}
		}

		mu.Lock()
		upgrades = append(upgrades, pathSet{path: path, pkgMods: pkgMods, err: err})
		mu.Unlock()
		return false
	}

	r.loadPackages(ctx, patterns, findPackage)

	// 由于我们同时建立了候选人名单，他们可能处于不确定的顺序。我们希望“go get”是完全确定的，
	// 包括它选择报告的错误，所以对候选
	// 进入一个确定性但任意的顺序。
	sort.Slice(upgrades, func(i, j int) bool {
		return upgrades[i].path < upgrades[j].path
	})
	return upgrades
}

// loadPackages加载与给定模式匹配的包，为可能需要更改
// findPackage函数。
// 构建列表的每个包调用
// 
// loadPackages为从主模块外的
// 模块加载的每个包调用findPackage函数。如果由于查询需要更改提供
// 包的模块或版本，findPackage可能会返回false 
// 并且不会加载该包的导入。
// 
// loadPackages还为每个导入的包
// 调用findPackage函数，该函数既不存在于标准库中，也不存在于
// 生成列表中的任何模块中。
func (r *resolver) loadPackages(ctx context.Context, patterns []string, findPackage func(ctx context.Context, path string, m module.Version) (versionOk bool)) {
	opts := modload.PackageOpts{
		Tags:                     imports.AnyTags(),
		VendorModulesInGOROOTSrc: true,
		LoadTests:                *getT,
		AssumeRootsImported:      true, // 在“go get foo”之后，应该建立foo的导入。
		SilencePackageErrors:     true, // 可能会通过后续升级或降级进行修复。
	}

	opts.AllowPackage = func(ctx context.Context, path string, m module.Version) error {
		if m.Path == "" || m.Version == "" {
			// 标准库和主要模块中的软件包已达到其最新（也是唯一）可用版本。
			return nil
		}
		if ok := findPackage(ctx, path, m); !ok {
			return errVersionChange
		}
		return nil
	}

	_, pkgs := modload.LoadPackages(ctx, opts, patterns...)
	for _, path := range pkgs {
		const (
			parentPath  = ""
			parentIsStd = false
		)
		_, _, err := modload.Lookup(parentPath, parentIsStd, path)
		if err == nil {
			continue
		}
		if errors.Is(err, errVersionChange) {
			// 我们已经在加载过程中添加了候选项。
			continue
		}

		var (
			importMissing *modload.ImportMissingError
			ambiguous     *modload.AmbiguousImportError
		)
		if !errors.As(err, &importMissing) && !errors.As(err, &ambiguous) {
			// 这个软件包是我们关心的东西的依赖项，它有一些我们无法通过版本更改来解决的问题。
			// 将错误留给最后的LoadPackages调用。
			continue
		}

		path := path
		r.work.Add(func() {
			findPackage(ctx, path, module.Version{})
		})
	}
	<-r.work.Idle()
}

// errVersionChange是一个哨兵错误，表示模块的版本需要更新，然后才能加载其依赖项。
var errVersionChange = errors.New("version change needed")

// resolveQueries解析附加到给定
// 查询和/或提供给定缺少的包依赖项所需的候选集。
// 
// resolveQueries首先从每个
// 附加到给定查询的明确路径集中解析一个模块版本。
// 
// 如果没有明确的查询导致生成列表发生更改，
// resolveQueries会重新访问模糊的候选查询并任意解析它们，以保证向前的进度。
// 
// 如果解析了所有路径集，但未对生成列表进行任何更改，则
// resolveQueries返回changed=false。
func (r *resolver) resolveQueries(ctx context.Context, queries []*query) (changed bool) {
	defer base.ExitIfErrors()

	// 注意：这是O（N²），在最坏的情况下是路径集的数量。
	// 
	// 如果我们按模块路径对路径集
	// 进行索引，那么我们可能会将其归结为O（N），这样我们只有在确定了包含包列表中某个模块的
	// 版本后，才能重新访问给定的路径集。
	// 
	// 然而，N往往很小，大多数候选集将只包含一个
	// 候选模块（因此它们将在第一次迭代中解析），因此对于
	// 现在我们将坚持简单的O（N²）方法。

	resolved := 0
	for {
		prevResolved := resolved

		for _, q := range queries {
			unresolved := q.candidates[:0]

			for _, cs := range q.candidates {
				if cs.err != nil {
					reportError(q, cs.err)
					resolved++
					continue
				}

				filtered, isPackage, m, unique := r.disambiguate(cs)
				if !unique {
					unresolved = append(unresolved, filtered)
					continue
				}

				if m.Path == "" {
					// 该查询不可行。在筛选之前，从
					// 中选择任意候选人，并“解决”该候选人以报告冲突。
					isPackage, m = r.chooseArbitrarily(cs)
				}
				if isPackage {
					q.matchesPackages = true
				}
				r.resolve(q, m)
				resolved++
			}

			q.candidates = unresolved
		}

		base.ExitIfErrors()
		if resolved == prevResolved {
			break // 没有明确的候选人。
		}
	}

	if resolved > 0 {
		if changed = r.updateBuildList(ctx, nil); changed {
			// 构建列表已更改，因此忽略任何剩余的模糊查询：
			// 它们现在可能由构建列表中的需求决定，我们
			// 更喜欢使用该列表，而不是任意版本。
			return true
		}
	}

	// 构建列表在下一次迭代中将与此
	// 迭代相同，因此任何不明确的查询都将保持不变。为了使
	// 取得进展，请随意但果断地解决它们。
	// 
	// 如果这导致版本冲突，用户可以重新运行'go get'
	// 为冲突的包或
	// 模块提供额外的显式版本。
	resolvedArbitrarily := 0
	for _, q := range queries {
		for _, cs := range q.candidates {
			isPackage, m := r.chooseArbitrarily(cs)
			if isPackage {
				q.matchesPackages = true
			}
			r.resolve(q, m)
			resolvedArbitrarily++
		}
	}
	if resolvedArbitrarily > 0 {
		changed = r.updateBuildList(ctx, nil)
	}
	return changed
}

// applyUpgrades消除了升级（或
// 提供）以前解析的包导入的可传递依赖项所需的候选集的歧义。
// 
// applyUpgrades通过在升级中从每个
// 路径集中添加一个模块版本来修改构建列表，然后将这些模块降级（或进一步升级）为
// 需要维护其他模块的任何已解析版本。
// applyUpgrades不会将新版本标记为已解决，因此它们仍然可以被其他查询（如通配符）进一步修改。
// 
// 如果解析了所有路径集，且未对生成列表进行任何更改，则
// applyUpgrades将返回changed=false。
func (r *resolver) applyUpgrades(ctx context.Context, upgrades []pathSet) (changed bool) {
	defer base.ExitIfErrors()

	// 任意添加一个“最新”版本，提供每个缺少的包，但
	// 不要将该版本标记为已解决：我们仍然希望允许显式
	// 查询修改生成的版本。
	var tentative []module.Version
	for _, cs := range upgrades {
		if cs.err != nil {
			base.Errorf("go: %v", cs.err)
			continue
		}

		filtered, _, m, unique := r.disambiguate(cs)
		if !unique {
			_, m = r.chooseArbitrarily(filtered)
		}
		if m.Path == "" {
			// 缺少的包裹没有可行的候选人。
			// 不要解决它。
			continue
		}
		tentative = append(tentative, m)
	}
	base.ExitIfErrors()

	changed = r.updateBuildList(ctx, tentative)
	return changed
}

// 消除歧义消除与其他模块冲突的cs中的候选模块
// 已解决的版本。如果只有一个（唯一的）
// 剩余的候选者，disambiguate将返回该候选者，以及
// 指示该结果是否解释cs。path as a package 
// 
// 注意：我们在这里只做非常简单的消歧。我们的目标是重现用户的意图，而不是找到人类无法找到的解决方案。在绝大多数情况下，我们希望每个路径集只有一个模块，但我们希望提供一些最小的附加工具，以便用户可以在命令行上添加一两个额外参数来解决简单的歧义。
func (r *resolver) disambiguate(cs pathSet) (filtered pathSet, isPackage bool, m module.Version, unique bool) {
	if len(cs.pkgMods) == 0 && cs.mod.Path == "" {
		panic("internal error: resolveIfUnambiguous called with empty pathSet")
	}

	for _, m := range cs.pkgMods {
		if _, ok := r.noneForPath(m.Path); ok {
			// 版本为“无”的查询会强制候选模块的版本为
			// “无”，因此我们不能为该模块使用任何其他版本。
			continue
		}

		if modload.MainModules.Contains(m.Path) {
			if m.Version == "" {
				return pathSet{}, true, m, true
			}
			// 主模块只能设置为自己的版本。
			continue
		}

		vr, ok := r.resolvedVersion[m.Path]
		if !ok {
			// m是该查询的可行答案，但其他答案也可能是可行的。
			filtered.pkgMods = append(filtered.pkgMods, m)
			continue
		}

		if vr.version != m.Version {
			// 某些查询强制候选模块使用除此
			// 版本之外的其他版本。
			// 
			// 该命令可能类似于
			// 
			// 去获取示例。com/foo/bar@none实例com/foo/bar/baz@latest
			// 
			// 在这种情况下，我们*无法*解析来自
			// 示例的包。com/foo/bar（因为它被限制为版本
			// /“none”），并且必须符合模块示例。com/foo@latest.
			continue
		}

		// 一些查询强制候选模块*到*候选版本。
		// 因此，该候选者是提供
		// 其包的唯一可行选择：任何其他选择都会导致此路径的导入
		// 不明确。ABCFDG 
		// 
		// If模块示例。com/foo和示例。com/foo/bar都提供
		// 包示例。com/foo/bar/baz，那么我们*必须*解析示例中的包
		// 。com/foo：如果我们改为从
		// 示例中解决它。com/foo/bar，我们会有两份包裹。
		return pathSet{}, true, m, true
	}

	if cs.mod.Path != "" {
		vr, ok := r.resolvedVersion[cs.mod.Path]
		if !ok || vr.version == cs.mod.Version {
			filtered.mod = cs.mod
		}
	}

	if len(filtered.pkgMods) == 1 &&
		(filtered.mod.Path == "" || filtered.mod == filtered.pkgMods[0]) {
		// 只有一个可行的模块包含具有给定路径的包
		// （到目前为止是常见情况），因此我们可以明确地解决它。
		return pathSet{}, true, filtered.pkgMods[0], true
	}

	if len(filtered.pkgMods) == 0 {
		// 所有可以作为包提供路径的模块与其他
		// 已解决的参数冲突。如果它可以引用一个模块，则返回该模块；
		// 否则，无法解析此路径集（我们将返回
		// zero module.Version）。
		return pathSet{}, false, filtered.mod, true
	}

	// 查询仍然不明确：至少有两个不同的模块
	// 与cs连接。路径可以参考。
	return filtered, false, module.Version{}, false
}

// ChoosearBitrary从给定集合中返回任意（但确定性）模块版本
// 。
// 
// Choosearly优先选择已在
// “go get”开头的构建列表中的模块路径，优先选择提供包的模块，而不是不提供包的模块，并选择第一个满足这些标准的模块（因此偏向于
// 更长的路径）。
func (r *resolver) chooseArbitrarily(cs pathSet) (isPackage bool, m module.Version) {
	// 希望升级已在生成列表中的某些模块。
	for _, m := range cs.pkgMods {
		if r.initialSelected(m.Path) != "none" {
			return true, m
		}
	}

	// 否则，任意选择提供包的第一个模块。
	if len(cs.pkgMods) > 0 {
		return true, cs.pkgMods[0]
	}

	return false, cs.mod
}

// checkPackageProblems重新加载给定模式的包并报告
// 缺少和不明确的包错误。它还报告了对已解析模块和构建命名包所需模块的撤销和
// 弃用。
// 如果我们之前有一个
// 并且在加载包时没有得到一个，那么它还会为构建列表中的每个更新模块添加一个总和。
// 
// 我们跳过了前面过程中丢失的包错误，因为我们希望自己解析路径集，但此时，我们没有足够的上下文
// 记录导致每个错误的包导入链。kangdefg
func (r *resolver) checkPackageProblems(ctx context.Context, pkgPatterns []string) {
	defer base.ExitIfErrors()

	// 查找，我们不希望加载既不相关也不可操作的信息。
	type modFlags int
	const (
		resolved modFlags = 1 << iota // 由'go get'解析的版本
		named                         // 在命令行上显式命名或提供命名包
		hasPkg                        // 需要构建命名包
		direct                        // 提供主模块
	)
	relevantMods := make(map[module.Version]modFlags)
	for path, reason := range r.resolvedVersion {
		m := module.Version{Path: path, Version: reason.version}
		relevantMods[m] |= resolved
	}

	// 重新加载包的直接依赖关系，报告丢失和不明确导入的错误。
	if len(pkgPatterns) > 0 {
		// LoadPackages将打印错误（因为它有更多的上下文），但不会退出，因为我们需要稍后加载收回。
		pkgOpts := modload.PackageOpts{
			VendorModulesInGOROOTSrc: true,
			LoadTests:                *getT,
			ResolveMissingImports:    false,
			AllowErrors:              true,
			SilenceNoGoErrors:        true,
		}
		matches, pkgs := modload.LoadPackages(ctx, pkgOpts, pkgPatterns...)
		for _, m := range matches {
			if len(m.Errs) > 0 {
				base.SetExitStatus(1)
				break
			}
		}
		for _, pkg := range pkgs {
			if dir, _, err := modload.Lookup("", false, pkg); err != nil {
				if dir != "" && errors.Is(err, imports.ErrNoGo) {
					// 由于dir是非空的，我们必须找到与包或其测试相关联的源文件
					// ErrNoGo必须
					// 表明这些源文件都不适用于此
					// 配置。如果我们真的在构建包（no-d 
					// 标志），那么我们将报告问题；否则，假设
					// 用户将在其他
					// 配置中构建或测试此包，并抑制错误。
					continue
				}

				base.SetExitStatus(1)
				if ambiguousErr := (*modload.AmbiguousImportError)(nil); errors.As(err, &ambiguousErr) {
					for _, m := range ambiguousErr.Modules {
						relevantMods[m] |= hasPkg
					}
				}
			}
			if m := modload.PackageModule(pkg); m.Path != "" {
				relevantMods[m] |= hasPkg
			}
		}
		for _, match := range matches {
			for _, pkg := range match.Pkgs {
				m := modload.PackageModule(pkg)
				relevantMods[m] |= named
			}
		}
	}

	reqs := modload.LoadModFile(ctx)
	for m := range relevantMods {
		if reqs.IsDirect(m.Path) {
			relevantMods[m] |= direct
		}
	}

	// 为命令行中提到的模块和模块加载收回
	// 需要构建命名包。我们关心的是间接
	// 依赖项的撤销，因为我们可能能够从这些依赖项中升级。
	type modMessage struct {
		m       module.Version
		message string
	}
	retractions := make([]modMessage, 0, len(relevantMods))
	for m, flags := range relevantMods {
		if flags&(resolved|named|hasPkg) != 0 {
			retractions = append(retractions, modMessage{m: m})
		}
	}
	sort.Slice(retractions, func(i, j int) bool { return retractions[i].m.Path < retractions[j].m.Path })
	for i := range retractions {
		i := i
		r.work.Add(func() {
			err := modload.CheckRetractions(ctx, retractions[i].m)
			if retractErr := (*modload.ModuleRetractedError)(nil); errors.As(err, &retractErr) {
				retractions[i].message = err.Error()
			}
		})
	}

	// 加载命令行中提到的模块的弃用。如果间接依赖项也是主模块的直接依赖项，则仅加载
	// 对间接依赖项的弃用。对纯间接依赖的反对是
	// 不可操作的。
	deprecations := make([]modMessage, 0, len(relevantMods))
	for m, flags := range relevantMods {
		if flags&(resolved|named) != 0 || flags&(hasPkg|direct) == hasPkg|direct {
			deprecations = append(deprecations, modMessage{m: m})
		}
	}
	sort.Slice(deprecations, func(i, j int) bool { return deprecations[i].m.Path < deprecations[j].m.Path })
	for i := range deprecations {
		i := i
		r.work.Add(func() {
			deprecation, err := modload.CheckDeprecation(ctx, deprecations[i].m)
			if err != nil || deprecation == "" {
				return
			}
			deprecations[i].message = modload.ShortMessage(deprecation, "")
		})
	}

	// 为之前有总和的更新模块加载总和。当我们更新一个
	// 模块时，我们可能会更新生成列表中的另一个模块，该模块在“all”中提供了一个
	// 包，而该包不是作为此“go get”命令的一部分加载的。
	// 如果我们不为该模块添加一个总和，构建可能会在以后失败。
	// 请注意，意外更新的软件包仍然可以从未知模块或构建列表中我们之前不需要的模块导入软件包。我们不能在不加载“全部”的情况下处理那个案子。
	sumErrs := make([]error, len(r.buildList))
	for i := range r.buildList {
		i := i
		m := r.buildList[i]
		mActual := m
		if mRepl := modload.Replacement(m); mRepl.Path != "" {
			mActual = mRepl
		}
		old := module.Version{Path: m.Path, Version: r.initialVersion[m.Path]}
		if old.Version == "" {
			continue
		}
		oldActual := old
		if oldRepl := modload.Replacement(old); oldRepl.Path != "" {
			oldActual = oldRepl
		}
		if mActual == oldActual || mActual.Version == "" || !modfetch.HaveSum(oldActual) {
			continue
		}
		r.work.Add(func() {
			if _, err := modfetch.DownloadZip(ctx, mActual); err != nil {
				verb := "upgraded"
				if semver.Compare(m.Version, old.Version) < 0 {
					verb = "downgraded"
				}
				replaced := ""
				if mActual != m {
					replaced = fmt.Sprintf(" (replaced by %s)", mActual)
				}
				err = fmt.Errorf("%s %s %s => %s%s: error finding sum for %s: %v", verb, m.Path, old.Version, m.Version, replaced, mActual, err)
				sumErrs[i] = err
			}
		})
	}

	<-r.work.Idle()

	// 先报告折旧，再报告收回，再报告取和错误。
	// 只有取和错误才是硬错误。
	for _, mm := range deprecations {
		if mm.message != "" {
			fmt.Fprintf(os.Stderr, "go: module %s is deprecated: %s\n", mm.m.Path, mm.message)
		}
	}
	var retractPath string
	for _, mm := range retractions {
		if mm.message != "" {
			fmt.Fprintf(os.Stderr, "go: warning: %v\n", mm.message)
			if retractPath == "" {
				retractPath = mm.m.Path
			} else {
				retractPath = "<module>"
			}
		}
	}
	if retractPath != "" {
		fmt.Fprintf(os.Stderr, "go: to switch to the latest unretracted version, run:\n\tgo get %s@latest\n", retractPath)
	}
	for _, err := range sumErrs {
		if err != nil {
			base.Errorf("go: %v", err)
		}
	}
	base.ExitIfErrors()
}

// reportChanges记录操作系统的版本更改。斯特德尔。
// 
// reportChanges只记录对命令行上命名的模块和go中显式需要的模块的更改。摩登派青年对间接需求的大多数更改
// 与用户无关，不会被记录。
// 
// 应该在WriteGoMod之后调用reportChanges。
func (r *resolver) reportChanges(oldReqs, newReqs []module.Version) {
	type change struct {
		path, old, new string
	}
	changes := make(map[string]change)

	// 收集与命令行参数匹配的模块中的更改。
	for path, reason := range r.resolvedVersion {
		old := r.initialVersion[path]
		new := reason.version
		if old != new && (old != "" || new != "none") {
			changes[path] = change{path, old, new}
		}
	}

	// 收集对go中明确需求的更改。摩登派青年
	for _, req := range oldReqs {
		path := req.Path
		old := req.Version
		new := r.buildListVersion[path]
		if old != new {
			changes[path] = change{path, old, new}
		}
	}
	for _, req := range newReqs {
		path := req.Path
		old := r.initialVersion[path]
		new := req.Version
		if old != new {
			changes[path] = change{path, old, new}
		}
	}

	sortedChanges := make([]change, 0, len(changes))
	for _, c := range changes {
		sortedChanges = append(sortedChanges, c)
	}
	sort.Slice(sortedChanges, func(i, j int) bool {
		return sortedChanges[i].path < sortedChanges[j].path
	})
	for _, c := range sortedChanges {
		if c.old == "" {
			fmt.Fprintf(os.Stderr, "go: added %s %s\n", c.path, c.new)
		} else if c.new == "none" || c.new == "" {
			fmt.Fprintf(os.Stderr, "go: removed %s %s\n", c.path, c.old)
		} else if semver.Compare(c.new, c.old) > 0 {
			fmt.Fprintf(os.Stderr, "go: upgraded %s %s => %s\n", c.path, c.old, c.new)
		} else {
			fmt.Fprintf(os.Stderr, "go: downgraded %s %s => %s\n", c.path, c.old, c.new)
		}
	}

	// TODO（golang.org/issue/33284）：命令行参数的属性更改。
	// 对于与命令行参数匹配的模块，这可能不是
	// 必需的，但对于主模块
	// 的不匹配的直接依赖项，这将非常有用。
}

// 由于查询q，解析模块m必须处于其指定版本（可能是
// “无”）的记录。如果其他一些查询强制模块m处于
// 不同版本，则resolve报告冲突错误。
func (r *resolver) resolve(q *query, m module.Version) {
	if m.Path == "" {
		panic("internal error: resolving a module.Version with an empty path")
	}

	if modload.MainModules.Contains(m.Path) && m.Version != "" {
		reportError(q, &modload.QueryMatchesMainModulesError{
			MainModules: []module.Version{{Path: m.Path}},
			Pattern:     q.pattern,
			Query:       q.version,
		})
		return
	}

	vr, ok := r.resolvedVersion[m.Path]
	if ok && vr.version != m.Version {
		reportConflict(q, m, vr)
		return
	}
	r.resolvedVersion[m.Path] = versionReason{m.Version, q}
	q.resolved = append(q.resolved, m)
}

// updateBuildList将模块加载器的全局生成列表更新为
// 与r.resolvedVersion一致，并包含其他模块
// 前提是它们与已解析的版本不冲突。
// 
// 如果附加模块与已解决的版本冲突，它们将被
// 降级为不冲突的版本（可能为“无”）。
// 
// 如果生成的生成列表与上次
// 调用updateBuildList生成的生成列表相同，则updateBuildList返回changed=false。
func (r *resolver) updateBuildList(ctx context.Context, additions []module.Version) (changed bool) {
	defer base.ExitIfErrors()

	resolved := make([]module.Version, 0, len(r.resolvedVersion))
	for mPath, rv := range r.resolvedVersion {
		if !modload.MainModules.Contains(mPath) {
			resolved = append(resolved, module.Version{Path: mPath, Version: rv.version})
		}
	}

	changed, err := modload.EditBuildList(ctx, additions, resolved)
	if err != nil {
		var constraint *modload.ConstraintError
		if !errors.As(err, &constraint) {
			base.Errorf("go: %v", err)
			return false
		}

		reason := func(m module.Version) string {
			rv, ok := r.resolvedVersion[m.Path]
			if !ok {
				panic(fmt.Sprintf("internal error: can't find reason for requirement on %v", m))
			}
			return rv.reason.ResolvedString(module.Version{Path: m.Path, Version: rv.version})
		}
		for _, c := range constraint.Conflicts {
			base.Errorf("go: %v requires %v, not %v", reason(c.Source), c.Dep, reason(c.Constraint))
		}
		return false
	}
	if !changed {
		return false
	}

	const defaultGoVersion = ""
	r.buildList = modload.LoadModGraph(ctx, defaultGoVersion).BuildList()
	r.buildListVersion = make(map[string]string, len(r.buildList))
	for _, m := range r.buildList {
		r.buildListVersion[m.Path] = m.Version
	}
	return true
}

func reqsFromGoMod(f *modfile.File) []module.Version {
	reqs := make([]module.Version, len(f.Require))
	for i, r := range f.Require {
		reqs[i] = r.Mod
	}
	return reqs
}

// isNoSuchModuleVersion报告err是否表示请求的模块
// 在请求的版本中不存在，或者是因为该模块根本不存在，或者是因为它不包含该特定版本。
func isNoSuchModuleVersion(err error) bool {
	var noMatch *modload.NoMatchingVersionError
	return errors.Is(err, os.ErrNotExist) || errors.As(err, &noMatch)
}

// isNoSuchPackageVersion报告err是否表示请求的
// 包在请求的版本中不存在，这可能是因为在该版本中不存在可能包含它的模块
// 或者因为存在的每个这样的模块
// 实际上并不包含该包。
func isNoSuchPackageVersion(err error) bool {
	var noPackage *modload.PackageNotInModuleError
	return isNoSuchModuleVersion(err) || errors.As(err, &noPackage)
}
